/*
 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#![no_main]
#![no_std]
#![allow(dead_code)]
#![allow(non_upper_case_globals)]

use panic_halt as _;

use cortex_m_semihosting::{debug, hprintln};

use core::{
    mem::zeroed,
    ptr::{read, write_volatile},
};

extern "C" {
    fn _estack();
}

pub unsafe extern "C" fn svc_handler() {
	hprintln!("svc_handler! ").unwrap();
}

pub unsafe extern "C" fn pendsv_handler() {
	hprintln!("pendsv_handler! ").unwrap();
}

pub unsafe extern "C" fn systick_handler() {
	hprintln!("systick_handler! ").unwrap();
}

pub unsafe extern "C" fn default_handler() {
	hprintln!("default_handler! ").unwrap();
}

#[link_section = ".isr_vector"]
#[used]
pub static BASE_VECTORS: [unsafe extern "C" fn(); 16] = [
    _estack,
    reset_handler,
    default_handler, // NMI
    default_handler,  // Hard Fault
    default_handler, // MemManage
    default_handler, // BusFault
    default_handler, // UsageFault
    default_handler,
    default_handler,
    default_handler,
    default_handler,
    svc_handler,         // SVC
    default_handler, // DebugMon
    default_handler,
    pendsv_handler, // PendSV
    systick_handler,     // SysTick
];

extern "C" {
	// These symbols come from `linker.ld`
	static mut _sbss: u32; // Start of .bss section
	static mut _ebss: u32; // End of .bss section
	static mut _sdata: u32; // Start of .data section
	static mut _edata: u32; // End of .data section
	static __rodata_regions_array_start: u32; // Start of .rodata section
	static mut __vectors_start:u32;
}


pub unsafe extern "C" fn reset_handler() {


	//unsafe{*(SCB_VTOR as *mut u32) =  &mut __vectors_start};

    // Initialize (Zero) BSS

	let mut sbss: *mut u32 = &mut _sbss;
	let ebss: *mut u32 = &mut _ebss;

	while sbss < ebss {
		write_volatile(sbss, zeroed());
		sbss = sbss.offset(1);
	}


    // Initialize Data

	let mut sdata: *mut u32 = &mut _sdata;
	let edata: *mut u32 = &mut _edata;
	let mut sidata: *const u32 = &__rodata_regions_array_start;

	while sdata < edata {
		write_volatile(sdata, read(sidata));
		sdata = sdata.offset(1);
		sidata = sidata.offset(1);
	}


    // Call user's main function
    main()
}

//systick config
pub const SystemCoreClock:u32 = 168000000;
pub const SysTick:u32 = 0xE000E010;
pub const SysTickCTL:u32 = SysTick;
pub const SysTickLoad:u32 = SysTick + 0x4;
pub const SysTickVal:u32 = SysTick + 0x8;

fn systick_config()
{
	unsafe{*(SysTickLoad as *mut u32) = SystemCoreClock / 1000 - 1};
	unsafe{*(SysTickVal as *mut u32) = 0};
	unsafe{*(SysTickCTL as *mut u32) = 1 | 1 << 1 | 1 << 2};
}

use utils::los_list::LosList; 
use kernel::los_memory;

#[no_mangle]
pub unsafe fn __aeabi_unwind_cpp_pr0() -> () {
  loop {}
}


fn test_mm() {
	los_memory::init(1024);
	hprintln!("Mem init success!").unwrap();

	let mem = los_memory::alloc(4);
	if mem.is_none() {
		hprintln!("Mem alloc failed!").unwrap();
		return;
	}
	hprintln!("Mem alloc success!").unwrap();

	let p = |m:&los_memory::Mem| {
		hprintln!("{:x} {:x} {:x} {:x}", m.read(0), m.read(1), m.read(2), m.read(3)).unwrap();
	};

	let mut mem = mem.unwrap();

	mem.write(&828_i32.to_be_bytes());
	p(&mem);

	los_memory::realloc(&mut mem, 16);
	mem.write(b"abcdefghijk");
	p(&mem);
}


fn main() -> ! {
    hprintln!("Hello,liteos! ").unwrap();
	hprintln!("mm test s! ").unwrap();
	test_mm();
	hprintln!("mm test e! ").unwrap();
	//list test
	let list = &mut LosList::new();
	list.init();

	assert!(!list.pst_prev.is_null() && !list.pst_next.is_null());
	assert!(list.pst_prev == list.pst_next);
	
	list.add(&mut LosList::new());
	list.add_tail(&mut LosList::new());
	list.add(&mut LosList::new());
	list.add(&mut LosList::new());
	list.add_tail(&mut LosList::new());

	let mut current = list;
	let mut count = 10;
	hprintln!("list test! ").unwrap();
	while count > 0 {
		hprintln!("{:?} - {:?}", current, current.pst_next);
		current = unsafe {&mut *current.pst_next};
		count -= 1;
	}

	//systick can work;
	//systick_config();

	// exit QEMU
    // NOTE do not run this on hardware; it can corrupt OpenOCD state
    debug::exit(debug::EXIT_SUCCESS);

    loop {}
}
